package cn.wokoba.dao.adapter.repository;

import cn.wokoba.dao.dao.IGroupBuyActivityDao;
import cn.wokoba.dao.dao.IGroupBuyOrderDao;
import cn.wokoba.dao.dao.IGroupBuyOrderListDao;
import cn.wokoba.dao.dao.INotifyTaskDao;
import cn.wokoba.dao.dao.po.GroupBuyActivity;
import cn.wokoba.dao.dao.po.GroupBuyOrder;
import cn.wokoba.dao.dao.po.GroupBuyOrderList;
import cn.wokoba.dao.dao.po.NotifyTask;
import cn.wokoba.service.dcc.DccService;
import cn.wokoba.service.trade.adapter.repository.ITradeRepository;
import cn.wokoba.service.trade.model.aggregate.GroupBuyOrderAggregate;
import cn.wokoba.service.trade.model.aggregate.GroupBuyTeamSettlementAggregate;
import cn.wokoba.service.trade.model.entity.*;
import cn.wokoba.service.trade.model.valobj.GroupBuyProgressVO;
import cn.wokoba.service.trade.model.valobj.TradeOrderStatusEnumVO;
import cn.wokoba.types.common.Constants;
import cn.wokoba.types.enums.ActivityStatusEnumVO;
import cn.wokoba.types.enums.GroupBuyOrderEnumVO;
import cn.wokoba.types.enums.ResponseCode;
import cn.wokoba.types.exception.AppException;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Repository
public class TradeRepository implements ITradeRepository {

    @Resource
    private IGroupBuyOrderDao groupBuyOrderDao;
    @Resource
    private IGroupBuyOrderListDao groupBuyOrderListDao;
    @Resource
    private IGroupBuyActivityDao groupBuyActivityDao;
    @Resource
    private INotifyTaskDao notifyTaskDao;
    @Resource
    private DccService dccService;

    @Override
    public MarketPayOrderEntity queryMarketPayOrderEntityByOutTradeNo(String userId, String outTradeNo) {
        GroupBuyOrderList groupBuyOrderListReq = new GroupBuyOrderList();
        groupBuyOrderListReq.setUserId(userId);
        groupBuyOrderListReq.setOutTradeNo(outTradeNo);
        GroupBuyOrderList groupBuyOrderListRes = groupBuyOrderListDao.queryGroupBuyOrderRecordByOutTradeNo(groupBuyOrderListReq);
        if (null == groupBuyOrderListRes) return null;

        return MarketPayOrderEntity.builder()
                .teamId(groupBuyOrderListRes.getTeamId())
                .orderId(groupBuyOrderListRes.getOrderId())
                .deductionPrice(groupBuyOrderListRes.getDeductionPrice())
                .tradeOrderStatusEnumVO(TradeOrderStatusEnumVO.valueOf(groupBuyOrderListRes.getStatus()))
                .build();
    }

    @Transactional(timeout = 500)
    @Override
    public MarketPayOrderEntity lockMarketPayOrder(GroupBuyOrderAggregate groupBuyOrderAggregate) {
        // 聚合对象信息
        UserEntity userEntity = groupBuyOrderAggregate.getUserEntity();
        PayActivityEntity payActivityEntity = groupBuyOrderAggregate.getPayActivityEntity();
        PayDiscountEntity payDiscountEntity = groupBuyOrderAggregate.getPayDiscountEntity();
        Integer userTakeOrderCount = groupBuyOrderAggregate.getUserTakeOrderCount();


        // 判断是否有团 - teamId 为空 - 新团、为不空 - 老团
        String teamId = payActivityEntity.getTeamId();
        if (StringUtils.isBlank(teamId)) {
            teamId = RandomStringUtils.randomNumeric(8);
            // 日期处理
            Date currentDate = new Date();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(currentDate);
            calendar.add(Calendar.MINUTE, payActivityEntity.getValidTime());

            // 构建拼团订单
            GroupBuyOrder groupBuyOrder = GroupBuyOrder.builder()
                    .teamId(teamId)
                    .activityId(payActivityEntity.getActivityId())
                    .source(payDiscountEntity.getSource())
                    .channel(payDiscountEntity.getChannel())
                    .originalPrice(payDiscountEntity.getOriginalPrice())
                    .deductionPrice(payDiscountEntity.getDeductionPrice())
                    .payPrice(payDiscountEntity.getPayPrice())
                    .targetCount(payActivityEntity.getTargetCount())
                    .completeCount(0)
                    .lockCount(1)
                    .validStartTime(currentDate)
                    .validEndTime(calendar.getTime())
                    .notifyUrl(payDiscountEntity.getNotifyUrl())
                    .build();

            // 写入记录
            groupBuyOrderDao.insert(groupBuyOrder);
        } else {
            // 更新记录 - 如果更新记录不等于1，则表示拼团已满，抛出异常
            int updateAddTargetCount = groupBuyOrderDao.updateAddLockCount(teamId);
            if (1 != updateAddTargetCount) {
                throw new AppException(ResponseCode.E0005.getCode());
            }
        }

        String orderId = RandomStringUtils.randomNumeric(12);
        GroupBuyOrderList groupBuyOrderListReq = GroupBuyOrderList.builder()
                .userId(userEntity.getUserId())
                .teamId(teamId)
                .orderId(orderId)
                .activityId(payActivityEntity.getActivityId())
                .startTime(payActivityEntity.getStartTime())
                .endTime(payActivityEntity.getEndTime())
                .goodsId(payDiscountEntity.getGoodsId())
                .source(payDiscountEntity.getSource())
                .channel(payDiscountEntity.getChannel())
                .originalPrice(payDiscountEntity.getOriginalPrice())
                .deductionPrice(payDiscountEntity.getDeductionPrice())
                .status(TradeOrderStatusEnumVO.CREATE.getCode())
                .outTradeNo(payDiscountEntity.getOutTradeNo())
                // 构建 bizId 唯一值；活动id_用户id_参与次数累加
                .bizId(payActivityEntity.getActivityId() + Constants.UNDERLINE + userEntity.getUserId() + Constants.UNDERLINE + (userTakeOrderCount + 1))
                .build();
        try {
            // 写入拼团记录
            groupBuyOrderListDao.insert(groupBuyOrderListReq);
        } catch (DuplicateKeyException e) {
            throw new AppException(ResponseCode.INDEX_EXCEPTION.getCode());
        }

        return MarketPayOrderEntity.builder()
                .orderId(orderId)
                .deductionPrice(payDiscountEntity.getDeductionPrice())
                .tradeOrderStatusEnumVO(TradeOrderStatusEnumVO.CREATE)
                .build();
    }

    @Override
    public GroupBuyProgressVO queryGroupBuyProgress(String teamId) {
        GroupBuyOrder groupBuyOrder = groupBuyOrderDao.queryGroupBuyProgress(teamId);
        if (null == groupBuyOrder) return null;
        return GroupBuyProgressVO.builder()
                .completeCount(groupBuyOrder.getCompleteCount())
                .targetCount(groupBuyOrder.getTargetCount())
                .lockCount(groupBuyOrder.getLockCount())
                .build();
    }

    @Override
    public GroupBuyActivityEntity queryGroupBuyActivityEntityByActivityId(Long activityId) {
        GroupBuyActivity groupBuyActivity = groupBuyActivityDao.selectOne(Wrappers
                .<GroupBuyActivity>lambdaQuery()
                .eq(GroupBuyActivity::getActivityId, activityId));
        return GroupBuyActivityEntity.builder()
                .activityId(groupBuyActivity.getActivityId())
                .activityName(groupBuyActivity.getActivityName())
                .discountId(groupBuyActivity.getDiscountId())
                .groupType(groupBuyActivity.getGroupType())
                .takeLimitCount(groupBuyActivity.getTakeLimitCount())
                .target(groupBuyActivity.getTarget())
                .validTime(groupBuyActivity.getValidTime())
                .status(ActivityStatusEnumVO.valueOf(groupBuyActivity.getStatus()))
                .startTime(groupBuyActivity.getStartTime())
                .endTime(groupBuyActivity.getEndTime())
                .tagId(groupBuyActivity.getTagId())
                .tagScope(groupBuyActivity.getTagScope())
                .build();
    }

    @Override
    public Integer queryOrderCountByActivityId(Long activityId, String userId) {
        return Math.toIntExact(groupBuyOrderListDao.selectCount(Wrappers.<GroupBuyOrderList>lambdaQuery()
                .eq(GroupBuyOrderList::getActivityId, activityId)
                .eq(GroupBuyOrderList::getUserId, userId)));
    }

    @Override
    public GroupBuyTeamEntity queryGroupBuyTeamByTeamId(String teamId) {
        GroupBuyOrder groupBuyOrder = groupBuyOrderDao.selectOne(Wrappers.<GroupBuyOrder>lambdaQuery()
                .eq(GroupBuyOrder::getTeamId, teamId));
        return GroupBuyTeamEntity.builder()
                .teamId(groupBuyOrder.getTeamId())
                .activityId(groupBuyOrder.getActivityId())
                .targetCount(groupBuyOrder.getTargetCount())
                .completeCount(groupBuyOrder.getCompleteCount())
                .lockCount(groupBuyOrder.getLockCount())
                .status(GroupBuyOrderEnumVO.valueOf(groupBuyOrder.getStatus()))
                .validStartTime(groupBuyOrder.getValidStartTime())
                .validEndTime(groupBuyOrder.getValidEndTime())
                .notifyUrl(groupBuyOrder.getNotifyUrl())
                .build();
    }

    @Transactional(timeout = 500)
    @Override
    public boolean settlementMarketPayOrder(GroupBuyTeamSettlementAggregate groupBuyTeamSettlementAggregate) {
        UserEntity userEntity = groupBuyTeamSettlementAggregate.getUserEntity();
        GroupBuyTeamEntity groupBuyTeamEntity = groupBuyTeamSettlementAggregate.getGroupBuyTeamEntity();
        TradePaySuccessEntity tradePaySuccessEntity = groupBuyTeamSettlementAggregate.getTradePaySuccessEntity();

        // 1. 更新拼团订单明细状态
        GroupBuyOrderList groupBuyOrderListReq = new GroupBuyOrderList();
        groupBuyOrderListReq.setUserId(userEntity.getUserId());
        groupBuyOrderListReq.setOutTradeNo(tradePaySuccessEntity.getOutTradeNo());
        groupBuyOrderListReq.setOutTradeTime(tradePaySuccessEntity.getOutTradeTime());
        int updateOrderListStatusCount = groupBuyOrderListDao.updateOrderStatus2COMPLETE(groupBuyOrderListReq);

        if (1 != updateOrderListStatusCount) {
            throw new AppException(ResponseCode.UPDATE_ZERO);
        }

        // 2. 更新拼团达成数量
        int updateAddCount = groupBuyOrderDao.updateAddCompleteCount(groupBuyTeamEntity.getTeamId());
        if (1 != updateAddCount) {
            throw new AppException(ResponseCode.UPDATE_ZERO);
        }

        // 3. 更新拼团完成状态
        if (groupBuyTeamEntity.getTargetCount() - groupBuyTeamEntity.getCompleteCount() == 1) {
            int updateOrderStatusCount = groupBuyOrderDao.updateOrderStatus2COMPLETE(groupBuyTeamEntity.getTeamId());
            if (1 != updateOrderStatusCount) {
                throw new AppException(ResponseCode.UPDATE_ZERO);
            }

            // 查询拼团交易完成外部单号列表
            List<String> outTradeNoList = groupBuyOrderListDao.queryGroupBuyCompleteOrderOutTradeNoListByTeamId(groupBuyTeamEntity.getTeamId());


            // 拼团完成写入回调任务记录
            NotifyTask notifyTask = new NotifyTask();
            notifyTask.setActivityId(groupBuyTeamEntity.getActivityId());
            notifyTask.setTeamId(groupBuyTeamEntity.getTeamId());
            notifyTask.setNotifyUrl(groupBuyTeamEntity.getNotifyUrl());
            notifyTask.setNotifyCount(0);
            notifyTask.setNotifyStatus(0);
//            notifyTask.setParameterJson(JSON.toJSONString(new HashMap<String, Object>() {{
//                put("teamId", groupBuyTeamEntity.getTeamId());
//                put("outTradeNoList", outTradeNoList);
//            }}));
            notifyTask.setParameterJson(JSON.toJSONString(Map.of(
                    "teamId", groupBuyTeamEntity.getTeamId(),
                    "outTradeNoList", outTradeNoList)));
            notifyTaskDao.insert(notifyTask);

            return true;
        }
        return false;
    }

    @Override
    public boolean isSCBlackIntercept(String source, String channel) {
        return dccService.isSCBlackIntercept(source, channel);
    }

    @Override
    public List<NotifyTaskEntity> queryUnExecutedNotifyTaskList(String teamId) {
        NotifyTask notifyTask = notifyTaskDao.selectOne(Wrappers.<NotifyTask>lambdaQuery()
                .eq(NotifyTask::getTeamId, teamId)
                .in(NotifyTask::getNotifyStatus, 0, 2));
        if (null == notifyTask) return new ArrayList<>();
        return Collections.singletonList(NotifyTaskEntity.builder()
                .teamId(notifyTask.getTeamId())
                .notifyUrl(notifyTask.getNotifyUrl())
                .notifyCount(notifyTask.getNotifyCount())
                .parameterJson(notifyTask.getParameterJson())
                .build());
    }

    @Override
    public List<NotifyTaskEntity> queryUnExecutedNotifyTaskList() {
        return notifyTaskDao.selectList(Wrappers.<NotifyTask>lambdaQuery()
                        .in(NotifyTask::getNotifyStatus, 0, 2)
                        .last("limit 50"))
                .stream().map(notifyTask -> NotifyTaskEntity.builder()
                        .teamId(notifyTask.getTeamId())
                        .notifyUrl(notifyTask.getNotifyUrl())
                        .notifyCount(notifyTask.getNotifyCount())
                        .parameterJson(notifyTask.getParameterJson())
                        .build()).toList();
    }

    @Override
    public int updateNotifyTaskStatusSuccess(String teamId) {
        return notifyTaskDao.updateNotifyTaskStatusSuccess(teamId);
    }

    @Override
    public int updateNotifyTaskStatusError(String teamId) {
        return notifyTaskDao.updateNotifyTaskStatusError(teamId);
    }

    @Override
    public int updateNotifyTaskStatusRetry(String teamId) {
        return notifyTaskDao.updateNotifyTaskStatusRetry(teamId);
    }


    @Override
    public Map<String, List<GroupBuyRefundEntity>> queryGroupBuyRefundEntity() {
        //查询超时未完成的拼团单
        List<GroupBuyOrder> groupBuyOrders = groupBuyOrderDao.selectList(Wrappers.<GroupBuyOrder>lambdaQuery()
                .select(GroupBuyOrder::getTeamId)
                .lt(GroupBuyOrder::getValidEndTime, new Date())
                .eq(GroupBuyOrder::getStatus, 0)
                .last("limit 10")
                .orderByAsc(GroupBuyOrder::getId));

        if (groupBuyOrders.isEmpty()) {
            return Map.of();
        }
        List<String> teamIds = groupBuyOrders.stream().map(GroupBuyOrder::getTeamId).toList();
        //查询需要退款的明细单
        List<GroupBuyOrderList> groupBuyOrderLists = groupBuyOrderListDao.selectList(Wrappers.<GroupBuyOrderList>lambdaQuery()
                .in(GroupBuyOrderList::getTeamId, teamIds)
                .eq(GroupBuyOrderList::getStatus, 1));
        //返回结果
        return groupBuyOrderLists.stream()
                .map(groupBuyOrderList -> GroupBuyRefundEntity.builder()
                        .outTradeTime(groupBuyOrderList.getOutTradeTime())
                        .goodsId(groupBuyOrderList.getGoodsId())
                        .payPrice(groupBuyOrderList.getOriginalPrice().subtract(groupBuyOrderList.getDeductionPrice()))
                        .orderId(groupBuyOrderList.getOrderId())
                        .bizId(groupBuyOrderList.getBizId())
                        .outTradeNo(groupBuyOrderList.getOutTradeNo())
                        .channel(groupBuyOrderList.getChannel())
                        .source(groupBuyOrderList.getSource())
                        .activityId(groupBuyOrderList.getActivityId())
                        .userId(groupBuyOrderList.getUserId())
                        .teamId(groupBuyOrderList.getTeamId())
                        .build())
                .collect(Collectors.groupingBy(GroupBuyRefundEntity::getTeamId));
    }

    @Override
    public void updateOrderListStatus2Refund(String orderId, String userId) {
        GroupBuyOrderList groupBuyOrderList = new GroupBuyOrderList();
        groupBuyOrderList.setOrderId(orderId);
        groupBuyOrderList.setUserId(userId);
        groupBuyOrderListDao.updateOrderStatus2Refund(groupBuyOrderList);
    }

    @Override
    public void updateOrderStatus2Fail(String teamId) {
        groupBuyOrderDao.updateOrderStatus2Fail(teamId);
    }
}
